home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / vol6n11.arc / REPEATS.ASM < prev    next >
Assembly Source File  |  1987-05-11  |  25KB  |  532 lines

  1. ;             REPEATS.ASM
  2. ;      Format: REPEATS [d:][/P]
  3. ; Returns with duplicate file names.
  4.  
  5. CODE SEGMENT                           ;*************************
  6. ASSUME CS:CODE,DS:CODE                 ;*                       *
  7. ORG 100H                               ;*  REMEMBER TO EXE2BIN  *
  8.                                        ;*                       *
  9. START:         JMP    BEGINNING        ;*************************
  10.  
  11. ;              DATA AREA
  12. ;              ---------
  13. COPYRIGHT      DB  'Copyright 1987 Ziff-Davis Publishing Co.',1AH
  14. PROGRAMMER     DB  'Michael J. Mefford'
  15. GLOBAL         DB  '*.*',0
  16. PARENT         DB  '..',0
  17. ROOT           DB  '\',0
  18.  
  19. DIR_OFFSET     DW  0
  20. CURRENT_DRIVE  DB  ?
  21. DIR_COUNT      DW  0
  22. FILE_COUNT     DW  0
  23. FILE_START     DW  ?
  24. END_OF_SPACE   DW  ?
  25.  
  26. PRINT_FLAG     DB  0
  27. MATCH_FLAG     DB  0
  28. DISPLAY_FLAG   DB  0
  29. SOURCE_FLAG    DB  0
  30.  
  31. SEARCHING      DB  13,10,'Searching ',0
  32. FOR            DB  ' for duplicate file names.',13,10
  33.                DB  'Loading directories...patience please',13,10,0
  34. LOADING_FILE   DB  'Loading file names...',0
  35. DIRECTORY      DB  13,10,'        Directory ',0
  36. NO_MATCHES     DB  7,13,10,'No duplicates found.',13,10,0
  37. DONE           DB  7,13,10,13,10,'Search sucessfully completed.',13,10,0
  38. NOT_ENOUGH     DB  'Not enough memory',0
  39.  
  40. DIR_ATTRIBUTE  EQU 10H
  41. ALL_FILES      EQU  6H
  42.  
  43. ;-------------------------------------------------------------;
  44. ; First allocate 64K and move the stack to the end of code.   ;
  45. ; Then get the current drive so we can restore upon exit.     ;
  46. ; Next check for a drive request and/or printer echo switch.  ;
  47. ; Save current directory. Display search request. And finally ;
  48. ; initialize the directory level subscripts to one.           ;
  49. ;-------------------------------------------------------------;
  50.  
  51. BEGINNING:     CLD                           ;All string instructions forward.
  52.                MOV    BX,1000H               ;64K (1000h paragraphs).
  53.                MOV    AH,4AH                 ;Modify allocated memory.
  54.                INT    21H
  55.                MOV    SI,OFFSET NOT_ENOUGH   ;Exit if 64K not available.
  56.                JNC    GOT_64K
  57.                JMP    PRINT_DONE
  58.  
  59. GOT_64K:       MOV    SP,OFFSET STACK_SPACE+1FFH   ;Move stack to end of code.
  60.                MOV    AH,19H                       ;Get the current drive
  61.                INT    21H
  62.                MOV    CURRENT_DRIVE,AL       ; and save.
  63.  
  64.                MOV    CL,DS:[80H]            ;Get the length of the argument.
  65.                CMP    CL,0                   ;If it's zero then no parameters.
  66.                JZ     NO_PARA
  67.                XOR    CH,CH                  ;Else, zero in high half.
  68.                MOV    SI,81H                 ;Point to parameter.
  69. NEXT_PARA:     CMP    BYTE PTR [SI],':'      ;Is it colon?
  70.                JNZ    CK_SWITCH              ;If no, check switch.
  71.                MOV    DL,[SI-1]              ;Else, get drive request.
  72.                AND    DL,5FH                 ;Capitalize.
  73.                SUB    DL,'A'                 ;Convert to DOS format.
  74.                MOV    AH,0EH                 ;And change drive.
  75.                INT    21H
  76. CK_SWITCH:     CMP    BYTE PTR [SI],'/'      ;Is it switch request?
  77.                JNZ    LOOP_PARA              ;If no, next parameter.
  78.                MOV    DL,[SI+1]              ;Else, get request.
  79.                AND    DL,5FH                 ;Capitalize.
  80.                CMP    DL,'P'                 ;Is it printer request?
  81.                JNZ    LOOP_PARA              ;If no, next parameter.
  82.                MOV    PRINT_FLAG,1           ;Else, flag printer echo.
  83. LOOP_PARA:     INC    SI                     ;Point to next byte
  84.                LOOP   NEXT_PARA              ; and get next byte.
  85.  
  86. NO_PARA:       MOV    BYTE PTR CURRENT_DIR,'\'
  87.                MOV    SI,OFFSET CURRENT_DIR+1     ;Save the current directory.
  88.                CALL   GET_DIR
  89.  
  90.                MOV    SI,OFFSET SEARCHING    ;Print "Searching ".
  91.                CALL   WRITE_STRING
  92.                MOV    AH,19H                 ;Get current drive.
  93.                INT    21H
  94.                MOV    DL,AL
  95.                ADD    DL,'A'                 ;Convert to ASCII
  96.                CALL   DISPLAY                ; and display.
  97.                MOV    DL,':'                 ;Display the colon.
  98.                CALL   DISPLAY
  99.                MOV    SI,OFFSET FOR          ;Display balance of intro.
  100.                CALL   WRITE_STRING
  101.  
  102.                CLD                           ;All string instructions will be
  103.                MOV    AL,1                   ; done in a forward direction.
  104.                MOV    CX,100                 ;Initialize directory subscripts
  105.                MOV    DI,OFFSET SUBSCRIPTS   ;to one.
  106.                REP    STOSB
  107.  
  108.                MOV    DX,OFFSET DTA          ;Point the disk transfer address
  109.                CALL   CHANGE_DTA             ; to the end of code.
  110.  
  111. ;------------------------------------------------------------;
  112. ; This routine will systematically change directories up and ;
  113. ; down the directory tree, and store the directory names.    ;
  114. ;------------------------------------------------------------;
  115.  
  116.                MOV    SI,OFFSET DIRECTORIES+1     ;Point to storage.
  117.                MOV    BP,OFFSET SUBSCRIPTS        ;Point to subscripts.
  118.                MOV    DX,OFFSET ROOT              ;Point to root.
  119.  
  120. STORE_DIR:     MOV    AH,0BH                 ;Check for Ctrl Break.
  121.                INT    21H
  122.                CALL   CHANGE_DIR
  123.                INC    DIR_COUNT
  124.                MOV    BYTE PTR [SI-1],'\'    ;DOS fails to preface with "\"
  125.                CALL   GET_DIR                ; so we have to.
  126.                ADD    SI,65                  ;Point to next storage.
  127.                ADD    DIR_OFFSET,65          ;Update the offset as well.
  128.                JMP    SHORT FIRST_DIR
  129.  
  130. PARENT_DIR:    CMP    BP,OFFSET SUBSCRIPTS   ;When we try to return to parent
  131.                JZ     FILENAMES              ; directory and are in root, we
  132.                MOV    DX,OFFSET PARENT       ; are done. Otherwise, change
  133.                CALL   CHANGE_DIR             ; to parent directory.
  134.                MOV    BYTE PTR DS:[BP],1     ;Put one back in previous level
  135.                DEC    BP                     ; and point to parent level.
  136.  
  137. FIRST_DIR:     XOR    BL,BL                  ;BL as pointer to directory no.
  138.                MOV    DX,OFFSET GLOBAL
  139.                MOV    CX,DIR_ATTRIBUTE       ;Ask for global match.
  140.                CALL   FIND_FIRST             ;Find first matching.
  141.                JC     PARENT_DIR
  142. CK_DIR:        CMP    BYTE PTR DTA+21,10H    ;If not a directory get next.
  143.                JNZ    NEXT_DIR
  144.                CMP    BYTE PTR DTA+30,'.'    ;If a dot directory get next.
  145.                JZ     NEXT_DIR
  146.                INC    BL                     ;Increment position in directory.
  147.                CMP    BL,DS:[BP]             ;Continue until new directory.
  148.                JNZ    NEXT_DIR
  149.                INC    BYTE PTR DS:[BP]       ;Update variables.
  150.                MOV    DX,OFFSET DTA+30
  151.                CALL   CHANGE_DIR
  152.                INC    BP
  153.                JMP    SHORT STORE_DIR
  154.  
  155. NEXT_DIR:      CALL   FIND_NEXT              ;Get all subdirectories in current
  156.                JC     PARENT_DIR             ; directory then go to parent.
  157.                JMP    SHORT CK_DIR
  158.  
  159. ;-----------------------------------------------;
  160. ; This routine finds and stores all file names. ;
  161. ;-----------------------------------------------;
  162.  
  163. FILENAMES:     CMP    DIR_COUNT,1            ;If only one directory
  164.                JNZ    ALLOCATE               ; then can't be any duplicates.
  165.                JMP    EXIT
  166. ALLOCATE:      ADD    SI,15                  ;Else, adjust for truncation.
  167.                MOV    CL,4                   ;Convert end of current storage
  168.                SHR    SI,CL                  ; into segment address.
  169.                MOV    BX,SI
  170.                MOV    AH,4AH                 ;Deallocate memory.
  171.                INT    21H
  172.  
  173.                MOV    BX,0FFFFH              ;See how much memory is left.
  174.                MOV    AH,48H
  175.                INT    21H
  176.                MOV    AH,4AH                 ;Ask for it all.
  177.                INT    21H
  178.  
  179.                MOV    CX,ES                  ;Get extra segment.
  180.                ADD    CX,SI                  ;Change to end of storage.
  181.                MOV    ES,CX
  182.                MOV    FILE_START,CX          ;Store as start of file storage.
  183.                ADD    BX,CX                  ;Add allocated memory.
  184.                MOV    END_OF_SPACE,BX        ;Store end of workspace.
  185.  
  186.                MOV    SI,OFFSET LOADING_FILE    ;Tell user, loading file names.
  187.                CALL   WRITE_STRING
  188.                MOV    DIR_OFFSET,OFFSET DIRECTORIES  ;Store directory start.
  189.                XOR    BP,BP                          ;BP as directory counter.
  190. FIRST_FILE:    MOV    AH,0BH                 ;Check for control break.
  191.                INT    21H
  192.                INC    BP                     ;Increment directory count.
  193.                CMP    BP,DIR_COUNT           ;Done all directories?
  194.                JA     DUPLICATES             ;If yes, search for duplicates.
  195.                MOV    DX,DIR_OFFSET          ;Else, change directory.
  196.                CALL   CHANGE_DIR
  197.                ADD    DIR_OFFSET,65          ;Point to next directory.
  198.                MOV    DX,OFFSET GLOBAL
  199.                MOV    CX,ALL_FILES
  200.                CALL   FIND_FIRST             ;Find first matching file.
  201.                JNC    STORE_FILE             ;If empty, next directory.
  202.                JMP    SHORT FIRST_FILE       ;Else, store data.
  203.  
  204. NEXT_FILE:     MOV    AX,ES                  ;Retrieve data segment.
  205.                ADD    AX,2                   ;Point to next storage.
  206.                MOV    ES,AX
  207.                MOV    SI,OFFSET NOT_ENOUGH   ;Assume out of memory.
  208.                CMP    AX,END_OF_SPACE        ;Is it true?
  209.                JB     CONTINUE               ;If no, continue.
  210.                JMP    EXIT                   ;Else, exit.
  211.  
  212. CONTINUE:      CALL   FIND_NEXT              ;Find next matching.
  213.                JC     FIRST_FILE             ;If done, next directory.
  214. STORE_FILE:    INC    FILE_COUNT             ;Else, increment file count.
  215.                MOV    SI,OFFSET DTA+22       ;Store filename data.
  216.                XOR    DI,DI                  ;Point to first byte.
  217.                MOV    AX,BP
  218.                STOSW                         ;Store directory number.
  219.                MOV    CX,4                   ;Store file date and size data.
  220.                REP    MOVSW
  221.  
  222.                MOV    CX,12                  ;Store 12 bytes of filename.
  223. NEXT_STORE:    LODSB                         ;Get a byte.
  224.                CMP    AL,0                   ;End of filename?
  225.                JZ     END_STORE              ;If yes, finish with blanks.
  226.                CMP    AL,'.'                 ;Is it the period?
  227.                JNZ    STORE_BYTE             ;If no, store.
  228.                SUB    CX,3                   ;Else store 3 spaces.
  229.                MOV    AL,32
  230.                REP    STOSB
  231.                ADD    CX,3
  232.                JMP    SHORT NEXT_STORE       ;Get next byte.
  233.  
  234. STORE_BYTE:    STOSB                         ;Store byte.
  235.                LOOP   NEXT_STORE             ;Get next byte.
  236. END_STORE:     MOV    AL,32                  ;Pad balance with spaces.
  237.                REP    STOSB
  238.                MOV    AL,0                   ;Tack on a zero for display
  239.                STOSB                         ; control.
  240.                JMP    SHORT NEXT_FILE        ;Get next filename.
  241.  
  242. ;-------------------------------------------------------------;
  243. ; This routine does the work of finding duplicate file names. ;
  244. ;-------------------------------------------------------------;
  245.  
  246. DUPLICATES:    MOV    WORD PTR ES:[0],0FFFFH    ;Tack on -1 signature.
  247.                MOV    SI,OFFSET SEARCHING    ;Tell user searching now.
  248.                CALL   WRITE_STRING
  249.                MOV    AX,FILE_START          ;Retrieve start of file names.
  250.                JMP    SHORT STORE_SOURCE
  251.  
  252. NEXT_SOURCE:   MOV    AH,0BH                 ;Check for Ctrl Break.
  253.                INT    21H
  254.                MOV    CS:SOURCE_FLAG,0       ;Reset source display flag.
  255.                MOV    AX,ES
  256.                ADD    AX,2                   ;Increment to next file name.
  257. STORE_SOURCE:  MOV    DS,AX
  258.                MOV    ES,AX
  259.                CMP    WORD PTR DS:[32],0FFFFH    ;End of file name storage?
  260.                JZ     EXIT                       ;If yes, we are done.
  261.                MOV    BP,ES:[0]              ;Retrieve directory number.
  262.                CMP    BP,0                   ;Have we matched this one before?
  263.                JZ     NEXT_SOURCE            ;If yes, get next.
  264.  
  265. NEXT_MATCH:    MOV    AX,DS                
  266.                ADD    AX,2                   ;Point to next target file name.
  267.                MOV    DS,AX
  268.                MOV    SI,0
  269.                LODSW                         ;Retrieve directory number.
  270.                CMP    AX,0FFFFH              ;End of file storage?
  271.                JZ     NEXT_SOURCE            ;If yes, get next file name.
  272.                CMP    AX,BP                  ;In same directory?
  273.                JZ     NEXT_MATCH             ;If yes, get next file name.
  274.  
  275.                MOV    SI,10                  ;Else, point to source and
  276.                MOV    DI,10                  ; and target file names.
  277.                MOV    CX,6
  278.                REPZ   CMPSW                  ;Are they duplicates?
  279.                JNZ    NEXT_MATCH             ;If no, next file name.
  280.                CALL   PRINT_MATCH            ;Else, print match.
  281.                MOV    WORD PTR DS:[0],0      ;Flag as matched.
  282.                JMP    SHORT NEXT_MATCH       ;Get next file name.
  283.  
  284. ;------------------------------------------------;
  285. ; Exit routine.  Restore default drive and       ;
  286. ; directories. Display appropriate exit message. ;
  287. ;------------------------------------------------;
  288.  
  289. EXIT:          PUSH   CS                          ;Restore data segment.
  290.                POP    DS
  291.                MOV    DX,OFFSET CURRENT_DIR       ;Restore default drive
  292.                CALL   CHANGE_DIR                  ; directory
  293.                MOV    DL,CURRENT_DRIVE            ; and drive.
  294.                MOV    AH,0EH
  295.                INT    21H
  296.                MOV    SI,OFFSET DONE
  297.                CMP    MATCH_FLAG,1                ;If match was found, display
  298.                JZ     PRINT_DONE                  ;"successful"
  299.                MOV    SI,OFFSET NO_MATCHES        ;else, display "none found".
  300. PRINT_DONE:    PUSH   CS
  301.                POP    DS
  302.                CALL   WRITE_STRING
  303.                INT    20H                         ;Terminate.
  304.  
  305.                ;*************;
  306.                ; SUBROUTINES ;
  307.                ;*************;
  308.  
  309. ;-------------------------------------------;
  310. ; These subroutines are DOS function calls. ;
  311. ;-------------------------------------------;
  312.  
  313. GET_DIR:       MOV    DL,0
  314.                MOV    AH,47H                 ;Get current directory.
  315.                INT    21H
  316.                RET
  317.  
  318. CHANGE_DIR:    MOV    AH,3BH                 ;Change current directory.
  319.                INT    21H
  320.                RET
  321.  
  322. CHANGE_DTA:    MOV    AH,1AH                 ;Set disk transfer address.
  323.                INT    21H
  324.                RET
  325.  
  326. FIND_FIRST:    MOV    AH,4EH                 ;Find first matching file.
  327.                INT    21H
  328.                RET
  329.  
  330. FIND_NEXT:     MOV    AH,4FH                 ;Find next matching file.
  331.                INT    21H
  332.                RET
  333.  
  334. ;------------------------------------------------------;
  335. ; Two subroutines: One adds carriage return; linefeed. ;
  336. ; The other pads the file name display with spaces.    ;
  337. ;------------------------------------------------------;
  338.  
  339. CR_LF:         MOV    DL,13
  340.                CALL   DISPLAY
  341.                MOV    DL,10
  342.                CALL   DISPLAY
  343.                RET
  344.  
  345. SPACES:        MOV    DL,32
  346.                CALL   DISPLAY
  347.                MOV    DL,32
  348.                CALL   DISPLAY
  349.                RET
  350.  
  351. ;-----------------------------------------------------;
  352. ; This subroutine handles all the output.  If /P was  ;
  353. ; included, output will be echoed to the printer.     ;
  354. ;-----------------------------------------------------;
  355.  
  356. DISPLAY:       CMP    CS:PRINT_FLAG,1        ;If /P, echo to the printer.
  357.                JNZ    NOT_PRINTER
  358.                MOV    AH,5                   ;Printer output.
  359.                INT    21H
  360. NOT_PRINTER:   MOV    AH,2                   ;Display output.
  361.                INT    21H
  362.                RET
  363.  
  364. WRITE_IT:      MOV    DL,AL
  365.                CALL   DISPLAY
  366. WRITE_STRING:  LODSB
  367.                CMP    AL,0                   ;Zero marks end of string.
  368.                JNZ    WRITE_IT
  369.                RET
  370.  
  371. ;------------------------------------------------------------------;
  372. ; This subroutine will print the duplicate file name and its path. ;
  373. ;------------------------------------------------------------------;
  374.  
  375. PRINT_MATCH:   PUSH   DS
  376.                MOV    CS:MATCH_FLAG,1        ;Flag that we have a duplicate.
  377.                CMP    CS:SOURCE_FLAG,1       ;Have we displayed source file?
  378.                JZ     SKIP_SOURCE            ;If yes, skip.
  379.                CALL   CR_LF
  380.                MOV    CX,39                  ;Separate duplicates with line.
  381. PRINT_LINE:    MOV    DL,'-'
  382.                CALL   DISPLAY
  383.                LOOP   PRINT_LINE
  384.                MOV    CS:SOURCE_FLAG,1       ;Flag displaying source.
  385.                MOV    AX,ES:[0]              ;Retrieve directory number.
  386.                CALL   PRINT_DIR
  387.                MOV    SI,ES                  ;Point to file name
  388.                CALL   WRITE_FILE             ;Display the file name and specs.
  389.  
  390. SKIP_SOURCE:   MOV    AX,DS:[0]              ;Retrieve directory number.
  391.                CALL   PRINT_DIR
  392.                MOV    SI,DS                  ;Point to file name.
  393.                CALL   WRITE_FILE
  394.                POP     DS
  395.                RET
  396.  
  397. ;----------------------------------------------;
  398. ; This subroutine displays the directory name. ;
  399. ;----------------------------------------------;
  400.  
  401. PRINT_DIR:     DEC    AX                     ;Adjust as a pointer.
  402.                MOV    BL,65                  ;Each directory record is 65.
  403.                MUL    BL
  404.                MOV    DI,AX
  405.                PUSH   DS
  406.  
  407.                PUSH   CS                     ;Restore our data segment.
  408.                POP    DS
  409.                MOV    SI,OFFSET DIRECTORY    ;Point to "Directory".
  410.                CALL   WRITE_STRING
  411.                MOV    SI,OFFSET DIRECTORIES  ;Point to directory name.
  412.                ADD    SI,DI
  413.                CALL   WRITE_STRING
  414.                CALL   CR_LF                  ;Add carriage return linefeed.
  415.  
  416.                POP    DS
  417.                RET
  418.  
  419. ;-------------------------------------------------------------------------;
  420. ; This subroutine handles displaying the file name, bytes, date and time. ;
  421. ;-------------------------------------------------------------------------;
  422.  
  423. WRITE_FILE:    PUSH   DS
  424.                MOV    DS,SI                  ;Point to file name segment.
  425.                MOV    SI,10                  ;Point to file name.
  426.                CALL   WRITE_STRING
  427.  
  428. FILE_SIZE:     MOV    DX,DS:[8]              ;Get high word of size
  429.                MOV    AX,DS:[6]              ; and low word of size.
  430.                MOV    CX,10000               ;Divide by 10,000.
  431.                DIV    CX
  432.                PUSH   DX                     ;Save remainder.
  433.                MOV    BX,AX
  434.                CALL   NUMBERS                ;Display ten thousands.
  435.                POP    BX                     ;Retrieve remainder.
  436.                CALL   THOUSANDS              ;Display thousands.
  437.  
  438. DATE:          CALL   SPACES                 ;Format to column 23.
  439.                MOV    SI,DS:[4]              ;Retrieve date.
  440.                MOV    BX,SI                  ;Get month four bits.
  441.                MOV    CL,5
  442.                ROR    BX,CL
  443.                AND    BX,15
  444.                MOV    CS:DISPLAY_FLAG,0      ;And display.
  445.                CALL   TENS
  446.  
  447.                MOV    DL,'-'                 ;Add hyphen.
  448.                CALL   DISPLAY
  449.                MOV    BX,SI
  450.                AND    BX,31                  ;Retrieve day five bits.
  451.                CALL   TENS                   ;And display.
  452.  
  453.                MOV    DL,'-'                 ;Add hyphen.
  454.                CALL   DISPLAY
  455.                MOV    BX,SI
  456.                MOV    CL,9                   ;Retrieve year seven bits.
  457.                ROR    BX,CL
  458.                AND    BX,127
  459.                ADD    BX,80
  460.                CALL   TENS                   ;And display.
  461.  
  462. TIME:          CALL   SPACES                 ;Format to column 33.
  463.                MOV    SI,DS:[2]              ;Get time.
  464.                MOV    BX,SI
  465.                MOV    CL,11
  466.                ROR    BX,CL
  467.                AND    BX,31                  ;Use hour five bits.
  468.                PUSH   BX
  469.                CMP    BX,12                  ;Past noon?
  470.                JBE    MERIDIAN
  471.                SUB    BX,12                  ;If yes, subtract 12.
  472. MERIDIAN:      CMP    BX,0                   ;Is it midnight?
  473.                JNZ    NOT_MIDNIGHT
  474.                MOV    BX,12                  ;If yes, display 12.
  475. NOT_MIDNIGHT:  MOV    CS:DISPLAY_FLAG,0
  476.                CALL   TENS                   ;And display.
  477.                MOV    DL,':'                 ;Add colon.
  478.                CALL   DISPLAY
  479.                MOV    BX,SI                  ;Retrieve minutes 6 bits.
  480.                MOV    CL,5
  481.                ROR    BX,CL
  482.                AND    BX,63
  483.                CALL   TENS                   ;And display.
  484.                MOV    DL,'p'                 ;Assume pm.
  485.                POP    BX
  486.                CMP    BX,12                  ;Is it noon or later?
  487.                JAE    PM                     ;If yes, display "p".
  488.                MOV    DL,'a'                 ;Else, display "a".
  489. PM:            CALL   DISPLAY
  490.                POP    DS
  491.                RET
  492.  
  493. ;----------------------------------------------------------------------------;
  494. ; This subroutine displays each decimal position, suppressing leading zeros. ;
  495. ;----------------------------------------------------------------------------;
  496.  
  497. NUMBERS:       MOV    CS:DISPLAY_FLAG,0      ;Reset the display flag.
  498.                MOV    CX,10000               ;Get ten thousands by dividing.
  499.                CALL   DIVIDE
  500. THOUSANDS:     MOV    CX,1000                ;Get thousands by dividing.
  501.                CALL   DIVIDE
  502.                MOV    CX,100                 ;Get hundreds by dividing.
  503.                CALL   DIVIDE
  504. TENS:          MOV    CX,10                  ;Get tens by dividing.
  505.                CALL   DIVIDE
  506.                MOV    CX,1                   ;Get ones by dividing.
  507.                CALL   DIVIDE
  508.                RET
  509.  
  510. DIVIDE:        MOV    AX,BX                  ;Number in AX
  511.                XOR    DX,DX                  ; and zero in DX
  512.                DIV    CX                     ; divide by CX
  513.                MOV    BX,DX                  ; remainder into BX
  514.                MOV    DL,AL                  ; and quotient into DL.
  515.                OR     CS:DISPLAY_FLAG,AL     ;If non zero indicate by flag.
  516. FLAG:          CMP    CS:DISPLAY_FLAG,0      ;Has there been a display?
  517.                JNZ    DISP_NUMBER            ;If yes, display.
  518.                MOV    DL,-10H                ;Else, display space.
  519. DISP_NUMBER:   ADD    DL,30H                 ;Convert hexadecimal to decimal
  520.                CALL   DISPLAY                ;And display.
  521. END_LINE:      RET
  522.  
  523. STACK_SPACE:
  524. DTA            EQU    STACK_SPACE+200H
  525. SUBSCRIPTS     EQU    DTA+65
  526. CURRENT_DIR    EQU    SUBSCRIPTS+100
  527. STORAGE        EQU    CURRENT_DIR+65
  528. DIRECTORIES    EQU    STORAGE+44
  529.  
  530. CODE ENDS
  531. END  START
  532.